﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Web;

namespace MdflCommonUtils {
    public class HttpUtil {
        static HttpUtil() {
            //绕过SSL验证
            ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
        }

        private const string applicationContentType = "application/json";
        private const string xmlContentType = "text/xml";
        private const string plainContentType = "text/plain";

        private const string defaultCharSet = "utf-8";

        private const int defaultTimeOut = 30;

        private const string httpMethodPost = "POST";
        private const string httpMethodGet = "GET";

        /// <summary>
        /// POST body到地址并返回
        /// </summary>
        /// <param name="url">post url</param>
        /// <param name="bodyData">post data</param>
        /// <param name="httpStatusCode">Http状态码</param>
        /// <param name="charset">编码</param>
        /// <param name="timeout">超时时间 单位秒</param>
        /// <param name="dictHeader">Http Header设置</param>
        /// <param name="contentType">Http ContentType设置</param>
        /// <returns></returns>
        public static string HttpPostBody(string url, string bodyData, out HttpStatusCode httpStatusCode, string charset = defaultCharSet, int timeout = defaultTimeOut, Dictionary<string, string> dictHeader = null, string contentType = "") {
            if(string.IsNullOrEmpty(contentType)) {
                if((bodyData.StartsWith("{") && bodyData.EndsWith("}")) || (bodyData.StartsWith("[") && bodyData.EndsWith("]"))) {
                    contentType = applicationContentType;
                } else if(bodyData.StartsWith("<") && bodyData.EndsWith(">")) {
                    contentType = xmlContentType;
                } else {
                    contentType = plainContentType;
                }
            }
            HttpWebRequest httpWebRequest = BuildHttpWebRequest(url, httpMethodPost, charset, timeout, dictHeader, contentType);
            return DoHttpRequest(httpWebRequest, bodyData, out httpStatusCode, charset);
        }

        /// <summary>
        /// POST body到地址并返回
        /// </summary>
        /// <param name="url">post url</param>
        /// <param name="bodyData">post data</param>
        /// <param name="charset">编码</param>
        /// <param name="timeout">超时时间 单位秒</param>
        /// <param name="dictHeader">Http Header设置</param>
        /// <param name="contentType">Http ContentType设置</param>
        /// <returns></returns>
        public static string HttpPostBody(string url, string bodyData, string charset = defaultCharSet, int timeout = defaultTimeOut, Dictionary<string, string> dictHeader = null, string contentType = "") {
            return HttpPostBody(url, bodyData, out _, charset, timeout, dictHeader, contentType);
        }

        /// <summary>
        /// POST form到地址并返回
        /// </summary>
        /// <param name="url">post url</param>
        /// <param name="dictForm">form键值对字典</param>
        /// <param name="httpStatusCode">Http状态码</param>
        /// <param name="charset">编码</param>
        /// <param name="timeout">超时时间 单位秒</param>
        /// <param name="dictHeader">Http Header设置</param>
        /// <returns></returns>
        public static string HttpPostForm(string url, Dictionary<string, string> dictForm, out HttpStatusCode httpStatusCode, string charset = defaultCharSet, int timeout = defaultTimeOut, Dictionary<string, string> dictHeader = null) {
            HttpWebRequest httpWebRequest = BuildHttpWebRequest(url, httpMethodPost, charset, timeout, dictHeader, "application/x-www-form-urlencoded");
            StringBuilder stringBuilder = new StringBuilder();
            if(dictForm != null) {
                int keyIndex = 0;
                foreach(KeyValuePair<string, string> keyValue in dictForm) {
                    if(keyIndex > 0) {
                        stringBuilder.Append("&");
                    }
                    stringBuilder.Append(HttpUtility.UrlEncode(keyValue.Key)).Append("=").Append(HttpUtility.UrlEncode(keyValue.Value));
                    keyIndex++;
                }
            }
            return DoHttpRequest(httpWebRequest, stringBuilder.ToString(), out httpStatusCode, charset);
        }

        /// <summary>
        /// POST form到地址并返回
        /// </summary>
        /// <param name="url">post url</param>
        /// <param name="dictForm">form键值对字典</param>
        /// <param name="charset">编码</param>
        /// <param name="timeout">超时时间 单位秒</param>
        /// <param name="dictHeader">Http Header设置</param>
        /// <returns></returns>
        public static string HttpPostForm(string url, Dictionary<string, string> dictForm, string charset = defaultCharSet, int timeout = defaultTimeOut, Dictionary<string, string> dictHeader = null) {
            return HttpPostForm(url, dictForm, out _, charset, timeout, dictHeader);
        }

        private const string defaultSoapHeaderName = "SOAPAction";

        public static string HttpPostWebService(string url, string soapData, string charset = defaultCharSet, int timeout = defaultTimeOut, Dictionary<string, string> dictHeader = null) {
            if(dictHeader == null) {
                dictHeader = new Dictionary<string, string>() {
                    { defaultSoapHeaderName,"" }
                };
            } else {
                if(!dictHeader.ContainsKey(defaultSoapHeaderName)) {
                    dictHeader.Add(defaultSoapHeaderName, "");
                }
            }
            return HttpPostBody(url, soapData, charset, timeout, dictHeader, xmlContentType);
        }

        /// <summary>
        /// HttpGet方法
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="queryParam">url参数</param>
        /// <param name="charset">编码</param>
        /// <param name="timeout">超时时间 单位秒</param>
        /// <returns></returns>
        public static string HttpGet(string url, String queryParam = "", string charset = defaultCharSet, int timeout = defaultTimeOut, Dictionary<string, string> dictHeader = null, string contentType = "") {
            url += string.IsNullOrEmpty(queryParam) ? "" : $"?{queryParam}";
            HttpWebRequest httpWebRequest = BuildHttpWebRequest(url, httpMethodGet, charset, timeout, dictHeader);
            return DoHttpRequest(httpWebRequest, "", charset);
        }

        private static HttpWebRequest BuildHttpWebRequest(string url, string method, string charset = defaultCharSet, int timeout = defaultTimeOut, Dictionary<string, string> dictHeader = null, string contentType = "") {
            HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
            httpWebRequest.ContentType = $"{contentType};charset={charset}";
            httpWebRequest.Method = method;
            httpWebRequest.Credentials = CredentialCache.DefaultCredentials;
            httpWebRequest.Timeout = timeout * 1000;
            if(dictHeader != null) {
                foreach(KeyValuePair<string, string> keyValue in dictHeader) {
                    httpWebRequest.Headers.Add(keyValue.Key, keyValue.Value);
                }
            }
            return httpWebRequest;
        }

        private static string DoHttpRequest(HttpWebRequest httpWebRequest, string postData, string charset = defaultCharSet) {
            return DoHttpRequest(httpWebRequest, postData, out _, charset);
        }

        private static string DoHttpRequest(HttpWebRequest httpWebRequest, string postData, out HttpStatusCode httpStatusCode, string charset = defaultCharSet) {
            string strResponseContent = "";
            Encoding encoding = Encoding.GetEncoding(charset);

            if(postData.Length > 0) {
                byte [] dataBytes = encoding.GetBytes(postData);
                httpWebRequest.ContentLength = dataBytes.Length;
                if(httpWebRequest.ContentLength > 0) {
                    using(Stream requestStream = httpWebRequest.GetRequestStream()) {
                        requestStream.Write(dataBytes, 0, dataBytes.Length);
                    }
                }
            }

            using(HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse()) {
                using(Stream stream = httpWebResponse.GetResponseStream()) {
                    using(StreamReader streamReader = new StreamReader(stream, encoding)) {
                        strResponseContent = streamReader.ReadToEnd();
                    }
                }
                httpStatusCode = httpWebResponse.StatusCode;
            }
            return strResponseContent;
        }
    }
}
